//
// Created by squbirreland on 2021/11/5.
//
#include <stdlib.h>
#include <string.h>
#include "array.h"

struct Array *new_array(usize init_size, usize type_size) {
    struct Array *array = malloc(sizeof(struct Array));
    array->size = 0;
    if (!init_size) {
        init_size = 1;
    }
    array->cap = init_size;
    array->type_size = type_size;
    array->array_p = malloc(type_size * init_size);
    return array;
}

struct Array *as_array(void *p, usize type_size, usize size) {
    if (p == NULL || type_size == 0 || size == 0) {
        return NULL;
    }
    struct Array *array = malloc(sizeof(struct Array));
    array->size = size;
    array->cap = size;
    array->type_size = type_size;
    array->array_p = p;
    return array;
}

void free_array(struct Array *array) {
    free(array->array_p);
    free(array);
}

void array_expansion(struct Array *array) {
    void *old_p = array->array_p;
    void *new_p = malloc(array->type_size * array->cap * 2);
    memcpy(new_p, old_p, array->cap * array->type_size);
    array->array_p = new_p;
    array->cap *= 2;
    free(old_p);
}

usize array_push(struct Array *array, const void *value) {
    if (array->size == array->cap) {
        array_expansion(array);
    }
    void *p = array->array_p + array->size * array->type_size;
    memcpy(p, value, array->type_size);
    array->size += 1;
    return array->size - 1;
}

void *array_pop(struct Array *array) {
    if (array->size == 0)return NULL;
    const void *old_p = array->array_p + (array->size - 1) * array->type_size;
    void *new_p = malloc(array->type_size);
    memcpy(new_p, old_p, array->type_size);
    array->size -= 1;
    return new_p;
}

void *array_get(struct Array *array, usize index) {
    if (index < array->size)
        return array->array_p + array->type_size * index;
    else return NULL;
}

void *array_remove(struct Array *array, usize index) {
    if (array->size - 1 < index)return NULL;
    const void *old_p = array->array_p + array->type_size * index;
    void *new_p = malloc(array->type_size);
    memcpy(new_p, old_p, array->type_size);
    for (usize i = index; i < array->size - 1; ++i) {
        void *current_p = array->array_p + array->type_size * i;
        void *next_p = current_p + array->type_size;
        memcpy(next_p, current_p, array->type_size);
    }
    array->size -= 1;
    return new_p;
}